
/**
 * AppleIIGo
 * Speaker class
 * (C) 2008 by Marc S. Ressl (mressl@umich.edu)
 * Released under the GPL
 * Based on Blargg's http://www.slack.net/~ant/bl-synth
 */

#include <math.h>
#include "Speaker.h"

Speaker::Speaker(Motherboard * motherboard, UINT32 speakerType) :
Device(motherboard, "Speaker") {
	this->speakerType = speakerType;
	
	initDelta();
}

void Speaker::onDevicesConnected() {
	timingGenerator = motherboard->getTimingGenerator();
}

void Speaker::onFrameEnd() {
	integrateDeltaBuffer();
}

void Speaker::toggleSpeakerOutput() {
	addDelta();
}

void Speaker::toggleCassetteOutput() {
	addDelta();
}

bool Speaker::isCassetteInputHigh() {
	return false;
}

void Speaker::initDelta() {
	double step[SPEAKERSTEP_SAMPLENUM];
	
	for (UINT32 index = 0; index < SPEAKERSTEP_SAMPLENUM; index++)
		step[index] = (index < SPEAKERSTEP_ONES) ? 0.5 : 1.0;
	
	for (UINT32 harmonicIndex = 1; harmonicIndex < SPEAKERSTEP_HARMONICNUM;
		harmonicIndex += 2) {
		double gain = (2 / M_PI) / harmonicIndex;
		double indexToPhase =
			(2 * M_PI / SPEAKERSTEP_SQUAREWAVEPERIOD) * harmonicIndex;
		for (UINT32 index = 0; index < SPEAKERSTEP_ONES; index++)
			step[index] += gain * sin(indexToPhase *
									  (index - SPEAKERSTEP_SAMPLENUM / 2 + 1));
	}
	
	for (UINT32 phaseIndex = 0; phaseIndex < SPEAKERPHASE_NUM; phaseIndex++) {
		double lastValue = 0.0;
		SINT16 quantizationError = SPEAKER_VOLUME;
		for (UINT32 index = 0; index < SPEAKERDELTA_SAMPLENUM; index++) {
			double value =
				step[index * SPEAKERPHASE_NUM +
					 (SPEAKERPHASE_NUM - 1 - phaseIndex)];
			SINT16 intValue = SPEAKER_VOLUME * (value - lastValue);
			lastValue = value;
			quantizationError -= intValue;
			delta[phaseIndex][index] = intValue;
		}
		delta[phaseIndex][SPEAKERDELTA_SAMPLENUM / 2 + 1] += quantizationError;
	}
	
	isSpeakerHigh = false;
	deltaValue = 0;
	dcFilterX1 = 0;
	dcFilterY1 = 0;
}

void Speaker::addDelta() {
	UINT32 phaseIndex = 0;
	//(UINT32) timingGenerator->getAudioFrameSampleIndex() *
	//	SPEAKERPHASE_NUM * audioFrameSampleNum / audioFrameClockNum;
	
	UINT32 bufferIndex = phaseIndex >> SPEAKERPHASE_BITNUM;
	phaseIndex &= (SPEAKERPHASE_NUM - 1);
	
	if (isSpeakerHigh) {
		isSpeakerHigh = false;
		for (UINT32 index = 0; index < SPEAKERDELTA_SAMPLENUM; index++)
			deltaBuffer[bufferIndex + index] -= delta[phaseIndex][index];
	} else {
		isSpeakerHigh = true;
		for (UINT32 index = 0; index < SPEAKERDELTA_SAMPLENUM; index++)
			deltaBuffer[bufferIndex + index] += delta[phaseIndex][index];
	}
}

void Speaker::integrateDeltaBuffer() {
	bool isToDo = true;

	// To-do: Fix buffer
/*	SINT32 * outputBuffer = audioOutputBuffer;
	for (UINT32 index = 0; index < audioFrameSampleNum; index++) {
		deltaValue += deltaBuffer[index];
		deltaBuffer[index] = deltaBuffer[index + audioFrameSampleNum];
		
		SINT32 dcFilterY0 = ((deltaValue - dcFilterX1) * 353 + 352 * 
			dcFilterY1) / 353;
		dcFilterY1 = dcFilterY0;
		dcFilterX1 = deltaValue;
		
		*outputBuffer++ = dcFilterY0;
		*outputBuffer++ = dcFilterY0;
	}

	for (UINT32 index = 0; index < (SPEAKERDELTA_SAMPLENUM - 1); index++)
		deltaBuffer[audioFrameSampleNum + index] = 0;*/
}
